/*
 * FTPFileSystem.java
 *
 * Created on December 1, 2006, 10:26 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package eu.somatik.somaftp.logic.ftp;

import com.glub.secureftp.bean.FTP;
import com.glub.secureftp.bean.FTPAbortableTransfer;
import com.glub.secureftp.bean.FTPConnectException;
import com.glub.secureftp.bean.FTPData;
import com.glub.secureftp.bean.FTPException;
import com.glub.secureftp.bean.FTPNoSuchFileException;
import com.glub.secureftp.bean.FTPNotADirectoryException;
import com.glub.secureftp.bean.Progress;
import com.glub.secureftp.bean.RemoteFile;
import com.glub.secureftp.bean.RemoteFileList;
import com.glub.secureftp.bean.g;
import eu.somatik.somaftp.SomaFTP;
import eu.somatik.somaftp.logic.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.swing.DefaultListModel;
import javax.swing.ListModel;
import javax.swing.TransferHandler;
import javax.swing.text.Document;
import javax.swing.tree.TreeModel;

/**
 *
 * @author francisdb
 */
public class FTPFileSystem extends AbstractFileSystem<FTPFile> {

    public static final String PROPERTY_PASSWORD = "password";
    public static final String PROPERTY_PORT = "port";
    
    private FTP ftp;
    
    private RemoteFileList remoteFileList;

    
    private OutputStream sendStream;
    private OutputStream receiveStream;
    
    /**
     * Creates a new instance of FTPFileSystem
     */
    public FTPFileSystem(SomaFTP somaFTP) {
        super(somaFTP, FTPFile.class);
        setProperty(PROPERTY_PORT, "21");
    }
    
    @Override
    public void connect(final DefaultListModel logModel) throws FileSystemException{
        
        logModel.clear();
        sendStream = new OutputStream() {
            private StringBuilder buffer = new StringBuilder();
            private int prev;
            public void write(int b) throws IOException {
                buffer.append((char)b);
                if(b == 10){
                    logModel.addElement(buffer.toString());
                    buffer.setLength(0);
                }
                prev = b;
            }
        };
        
        receiveStream = new OutputStream() {
            private StringBuilder buffer = new StringBuilder();
            private int prev;
            public void write(int b) throws IOException {
                buffer.append((char)b);
                //System.out.println(b+" "+(char)b);
                if(prev == 13 && b == 10){
                    logModel.addElement(buffer.toString().replaceAll((char)13 + "" + (char)10,"\n"));
                    buffer.setLength(0);
                }
                prev = b;
            }
        };

        ftp = new FTP(getProperty(PROPERTY_HOST), Integer.valueOf(getProperty(PROPERTY_PORT)), sendStream, receiveStream);
        try {
            ftp.connect();
            System.out.println(getProperty(PROPERTY_PASSWORD));
            ftp.login(getProperty(PROPERTY_USER), getProperty(PROPERTY_PASSWORD));
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        } catch (FTPConnectException ex) {
            throw new FileSystemException(ex.getMessage());
        } catch (UnknownHostException ex){
            throw new FileSystemException("Unknown host: "+ex.getMessage());
        } catch (IOException ex) {
            throw new FileSystemException(ex.getClass().getSimpleName()+" "+ex.getMessage());
        } catch (FTPException ex) {
            ex.printStackTrace();
        }
    }
    
    public void disconnect(){
        if(ftp.isConnected()){
            try {
                ftp.logout();
            } catch (FTPException ex) {
                ex.printStackTrace();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
    
    
    public List<FileInterface> list(boolean includeParent){
        List<FileInterface> list = new LinkedList<FileInterface>();
        try {
            if(ftp == null){
                throw new FTPException("Not connected");
            }

            remoteFileList = ftp.list();
            if(includeParent){
                RemoteFile lower = new RemoteFile("..");
                FTPFile file = new FTPFile(lower, this);
                list.add(file);
            }
            
            Iterator iterator = remoteFileList.iterator();
            while(iterator.hasNext()){
                list.add(new FTPFile((RemoteFile)iterator.next(), this));
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (FTPException ex) {
            ex.printStackTrace();
        }
        
        return list;
    }

    
    public String getPath(){
        String path = null;
        try {
            path = ftp.pwd();
        } catch (FTPException ex) {
            ex.printStackTrace();
        }
        return path;
    }


    public void changeDirectory(FTPFile dir) {
        if(!dir.isDirectory() && !dir.isLink()){
            throw new IllegalArgumentException(dir + " is not a directory");
        }
        try {
            ftp.chdir(dir.getFileObject());
        } catch (FTPNoSuchFileException ex) {
            ex.printStackTrace();
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        } catch (FTPNotADirectoryException ex) {
            ex.printStackTrace();
        } catch (FTPException ex) {
            ex.printStackTrace();
        }
    }

    public void receive(final FileTransfer transfer, InputStream is) throws FileSystemException{
        FileInterface requestedFile = transfer.getFromFile();
        
        Progress progress = new Progress() {
            public void finishProgress() {
                System.out.println("Stop");
                transfer.finish();
            }
            public void startProgress() {
                System.out.println("Start");
            }
            public void updateProgress(long current, long total) {
                //System.out.println(current + "/" + total);
            }
        };
        
        FTPAbortableTransfer abort = new FTPAbortableTransfer();
        try {
            ftp.append(is, requestedFile.getSize(), requestedFile.getName(), progress, abort);
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (FTPException ex) {
            throw new FileSystemException(ex.getMessage());
        }
        fireUpdate();
    }

    public void send(final FileTransfer transfer, final OutputStream os) {
        
        FileInterface requestedFile = transfer.getFromFile();
        
        FTPFile file = null;
        if(requestedFile instanceof FTPFile){
            file = (FTPFile) requestedFile;
        }else{
            throw new IllegalArgumentException();
        }
        RemoteFile remoteFile = file.getFileObject();
        
        Progress progress = new Progress() {
            public void finishProgress() {
                System.out.println("Stop");
                try {
                    os.close();
                    transfer.finish();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
            public void startProgress() {
                System.out.println("Start");
            }
            public void updateProgress(long current, long total) {
                //System.out.println(current + "/" + total);
            }
        };
        FTPAbortableTransfer abort = new FTPAbortableTransfer();
        try {
            ftp.auto();
            ftp.retrieve(remoteFile, os, progress, abort);
        } catch (g ex) {
            ex.printStackTrace();
        } catch (FTPException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

   

    public void delete(Object object) throws FileSystemException{
        FTPFile file = cast(object);
        try {
            if(file.isDirectory()){
                ftp.rmdir(file.getFileObject());
            }else{
                ftp.delete(file.getFileObject());
            }
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        } catch (FTPException ex) {
            throw new FileSystemException(ex.getMessage());
        }
    }

    public boolean isAlwaysConnected() {
        return false;
    }

    public boolean isConnected() {
        return ftp.isConnected();
    }

    public String getUserName() {
        return ftp.getUser();
    }

    public FileInterface getFileObjectFor(String fileName) {
        RemoteFile remoteFile = null;
        RemoteFile curRemoteFile;
        for(int i =0; i<remoteFileList.size() && remoteFile == null;i++){
            curRemoteFile = (RemoteFile) remoteFileList.get(i);
            if(curRemoteFile.getFileName().equals(fileName) && !curRemoteFile.isDirectory()){
                remoteFile = curRemoteFile;
            }
        }
        // new file
        if(remoteFile == null){
            remoteFile = new RemoteFile(fileName);
        }
        FTPFile file = new FTPFile(remoteFile, this);
        return file;
    }

    public Protocol getProtocol() {
        return Protocol.FTP;
    }

    protected void cd(String path) {
        try {
            ftp.chdir(path);
        } catch (FTPNotADirectoryException ex) {
            ex.printStackTrace();
        } catch (FTPNoSuchFileException ex) {
            ex.printStackTrace();
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        } catch (FTPException ex) {
            ex.printStackTrace();
        }
    }

    public void mkdir(String name) {
        try {
            ftp.mkdir(name);
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        } catch (FTPException ex) {
            ex.printStackTrace();
        }
    }
    
}
